#pragma once
#include "Test.h"
#include <vector>

class TestSuite
{
public:
	typedef boost::shared_ptr<Test> SharedPtr;
	typedef std::vector<SharedPtr > VectorTests;
private:
	std::string s;
	VectorTests vectorTests;
public:
	TestSuite(std::string _s):s(_s){};
	~TestSuite(){};
	void addTest(SharedPtr _test){vectorTests.push_back(_test);};
	VectorTests getTests(){return vectorTests;};
	std::string getName(){return s;};
};


class TestSuiteManager
{
public:
	static void runTestSuite(TestSuite& _testSuite)
	{


		Logger::getOStream()<<std::endl<<std::endl<<"____________________";
		Logger::getOStream()<<std::endl<<"BEGIN_TEST_SUITE "<<_testSuite.getName();
		Logger::flush();

		TestSuite::VectorTests vectorTests=_testSuite.getTests();
		

		bool allTestsStatus=true;
		for(TestSuite::VectorTests::iterator it=vectorTests.begin();it!=vectorTests.end();it++)
		{
			Logger::getOStream()<<std::endl<<"__________";
			Logger::getOStream() << std::endl<<"BEGIN_TEST " << (*it)->getName().c_str();
			Logger::flush();

			
			float elapsedTime=0;
			bool testStatus=true;
			MyTimer timer;
			try
			{
				//static int iterations=8;

				//for(int i=0;i<iterations;i++)
				//{
				//	MyTimer timer;
				//	(*it)->run();
				//	elapsedTime+=timer.getElapsedTimeInSeconds();
				//}
				//elapsedTime/=(float)iterations;


				timer.reset();
				(*it)->run();
				

			}
			catch(std::exception& ex)
			{
				Logger::getOStream()<<std::endl<<"Exception: "<<ex.what();
				Logger::flush();
				testStatus=false;
				allTestsStatus=false;
			}
			elapsedTime+=timer.getElapsedTimeInSeconds();

			Logger::getOStream()<<std::endl<<"elapsedTime="<<elapsedTime;
			Logger::getOStream()<<std::endl<<"status="<<testStatus;
			Logger::getOStream()<<std::endl<<"END_TEST "<<(*it)->getName().c_str();
			Logger::flush();
		}

		Logger::getOStream()<<std::endl<<std::endl<<"AllTestsStatus="<<allTestsStatus;
		Logger::flush();
	

		Logger::getOStream()<<std::endl<<std::endl<<"END_TEST_SUITE "<<_testSuite.getName();
		Logger::flush();
		Logger::saveToFile();
	}
};


namespace TestSuites
{
	class Example1: public TestSuite
	{
	public:
		Example1():TestSuite("TestSuites::Example1")
		{

			addTest(Test::SharedPtr(new Tests::Example));
			addTest(Test::SharedPtr(new Tests::Example));
		}
	};

	class Example2: public TestSuite
	{
	public:
		Example2():TestSuite("TestSuites::Example2")
		{

			//invalid output
			//const unsigned int OBSERVATION_VECTOR_SIZE=10;
			//const unsigned int NUMBER_OF_OBSERVATIONS=10000;
			//const unsigned int NUMBER_OF_CENTROIDS=100;
			//typedef KMeansStandardV1_Util<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::GenerateAlgorithmDataRandom 
			//	GenerateAlgorithmData;

			const unsigned int OBSERVATION_VECTOR_SIZE=10;
			const unsigned int NUMBER_OF_OBSERVATIONS=10000;
			const unsigned int NUMBER_OF_CENTROIDS=1000;
			typedef Algorithm::KMeansStandardV1_Util<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::GenerateAlgorithmDataRandom 
				GenerateAlgorithmData;

			addTest(Test::SharedPtr(new Tests::KMeansStandardV1Comparison1<GenerateAlgorithmData,OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::NonConcurrent));
			addTest(Test::SharedPtr(new Tests::KMeansStandardV1Comparison1<GenerateAlgorithmData,OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::ConcurrentV1));
		}
	};




	class Example3: public TestSuite
	{
	public:
		Example3():TestSuite("TestSuites::Example3")
		{


			const unsigned int OBSERVATION_VECTOR_SIZE=1;
			const unsigned int NUMBER_OF_OBSERVATIONS=5;
			const unsigned int NUMBER_OF_CENTROIDS=1;
			typedef Algorithm::KMeansStandardV1_Util<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::GenerateAlgorithmDataRandom 
				GenerateAlgorithmData;

			addTest(Test::SharedPtr(new Tests::KMeansStandardV1Comparison1<GenerateAlgorithmData,OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::NonConcurrent));
			addTest(Test::SharedPtr(new Tests::KMeansStandardV1Comparison1<GenerateAlgorithmData,OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::ConcurrentV1));

		}
	};



	class Example4: public TestSuite
	{
	public:
		Example4():TestSuite("TestSuites::Example4")
		{


			const unsigned int OBSERVATION_VECTOR_SIZE=8;
			const unsigned int NUMBER_OF_OBSERVATIONS=512;
			const unsigned int NUMBER_OF_CENTROIDS=256;
			typedef Algorithm::KMeansStandardV1_Util<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::GenerateAlgorithmDataRandom 
				GenerateAlgorithmData;

			addTest(Test::SharedPtr(new Tests::KMeansStandardV1Comparison1<GenerateAlgorithmData,OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::NonConcurrent));
			addTest(Test::SharedPtr(new Tests::KMeansStandardV1Comparison1<GenerateAlgorithmData,OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::ConcurrentV1));
			addTest(Test::SharedPtr(new Tests::KMeansStandardV1Comparison1<GenerateAlgorithmData,OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::ConcurrentV2));

		}
	};







	class TestSuiteError1: public TestSuite
	{
	public:
		TestSuiteError1():TestSuite("TestSuites1::TestSuiteError1")
		{
	

			//invalid output
			//const unsigned int OBSERVATION_VECTOR_SIZE=10;
			//const unsigned int NUMBER_OF_OBSERVATIONS=10000;
			//const unsigned int NUMBER_OF_CENTROIDS=100;
			//typedef KMeansStandardV1_Util<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::GenerateAlgorithmDataRandom 
			//	GenerateAlgorithmData;

			const unsigned int OBSERVATION_VECTOR_SIZE=10;
			const unsigned int NUMBER_OF_OBSERVATIONS=100;
			const unsigned int NUMBER_OF_CENTROIDS=100;
			typedef Algorithm::KMeansStandardV1_Util<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::GenerateAlgorithmDataRandom 
				GenerateAlgorithmData;

			addTest(Test::SharedPtr(new Tests::KMeansStandardV1Comparison1<GenerateAlgorithmData,OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::NonConcurrent));
			addTest(Test::SharedPtr(new Tests::KMeansStandardV1Comparison1<GenerateAlgorithmData,OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::ConcurrentV1));


		}
	};


	class Error2: public TestSuite
	{
	public:
		Error2():TestSuite("TestSuites::Error2")
		{


			const unsigned int OBSERVATION_VECTOR_SIZE=5;
			const unsigned int NUMBER_OF_OBSERVATIONS=10;
			const unsigned int NUMBER_OF_CENTROIDS=3;
			typedef Algorithm::KMeansStandardV1_Util<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::GenerateAlgorithmDataRandom 
				GenerateAlgorithmData;

			addTest(Test::SharedPtr(new Tests::KMeansStandardV1Comparison1<GenerateAlgorithmData,OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::NonConcurrent));
			addTest(Test::SharedPtr(new Tests::KMeansStandardV1Comparison1<GenerateAlgorithmData,OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::ConcurrentV1));
			addTest(Test::SharedPtr(new Tests::KMeansStandardV1Comparison1<GenerateAlgorithmData,OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS,NUMBER_OF_CENTROIDS>::ConcurrentV2));

		}
	};


}//namespace TestSuites